package cn.liangxxhu.rocketmq.repository;

import cn.liangxxhu.rocketmq.exception.EsException;
import cn.liangxxhu.rocketmq.param.BaseDocument;
import cn.liangxxhu.rocketmq.param.PageResult;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Query;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@RequiredArgsConstructor
public abstract class BaseEsService<T extends BaseDocument, ID extends Serializable> {

    protected final BaseEsRepository<T, ID> repository;
    protected final ElasticsearchOperations elasticsearchOperations;

    /**
     * 保存或更新文档。
     * 若实体存在 ID，则视为更新并刷新 updatedAt。
     * @param entity 文档实体
     * @return 保存后的文档
     */
    public T save(T entity) {
        if (entity.getId() != null) {
            // 如果是更新，更新时间戳
            entity.setUpdatedAt(LocalDateTime.now());
        }
        return repository.save(entity);
    }

    /**
     * 批量保存或更新文档。
     * 对于已有 ID 的实体，同步更新时间戳。
     * @param entities 文档集合
     * @return 保存后的文档集合
     */
    public List<T> batchSave(List<T> entities) {
        entities.forEach(entity -> {
            if (entity.getId() != null) {
                entity.setUpdatedAt(LocalDateTime.now());
            }
        });
        return repository.batchSave(entities);
    }

    /**
     * 根据 ID 查询文档，自动过滤逻辑删除的数据。
     * @param id 文档ID
     * @return 文档（可能为空）
     */
    public Optional<T> getById(ID id) {
        return repository.findById(id)
                .filter(entity -> !entity.isDeleted());
    }

    /**
     * 根据 ID 列表查询文档，自动过滤逻辑删除的数据。
     * @param ids 文档ID集合
     * @return 文档列表
     */
    public List<T> getByIds(List<ID> ids) {
        return repository.findByIdIn(ids).stream()
                .filter(entity -> !entity.isDeleted())
                .toList();
    }

    /**
     * 查询所有文档，自动过滤逻辑删除的数据。
     * @return 文档列表
     */
    public List<T> getAll() {
        return repository.getAll().stream()
                .filter(entity -> !entity.isDeleted())
                .toList();
    }

    /**
     * 分页查询所有文档，自动过滤逻辑删除的数据。
     * @param pageNum 页码（从1开始）
     * @param pageSize 每页大小（1-100）
     * @return 分页结果
     */
    public PageResult<T> getAll(int pageNum, int pageSize) {
        pageSize = validatePageSize(pageSize);
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);

        Page<T> page = repository.findAll(pageable);
        List<T> content = page.getContent().stream()
                .filter(entity -> !entity.isDeleted())
                .toList();

        return PageResult.of(content, page.getTotalElements(), pageNum, pageSize);
    }

    /**
     * 分页并排序查询所有文档，自动过滤逻辑删除的数据。
     * @param pageNum 页码（从1开始）
     * @param pageSize 每页大小（1-100）
     * @param sortField 排序字段
     * @param sortDirection 排序方向（asc/desc）
     * @return 分页结果
     */
    public PageResult<T> getAll(int pageNum, int pageSize, String sortField, String sortDirection) {
        pageSize = validatePageSize(pageSize);

        Sort.Direction direction = "asc".equalsIgnoreCase(sortDirection)
                ? Sort.Direction.ASC
                : Sort.Direction.DESC;

        Pageable pageable = PageRequest.of(
                pageNum - 1,
                pageSize,
                Sort.by(direction, sortField)
        );

        Page<T> page = repository.findAll(pageable);
        List<T> content = page.getContent().stream()
                .filter(entity -> !entity.isDeleted())
                .toList();

        return PageResult.of(content, page.getTotalElements(), pageNum, pageSize);
    }

    /**
     * 逻辑删除文档。
     * @param id 文档ID
     * @return 是否删除成功
     */
    public boolean deleteById(ID id) {
        return repository.findById(id)
                .map(entity -> {
                    entity.setDeleted(true);
                    entity.setUpdatedAt(LocalDateTime.now());
                    repository.save(entity);
                    return true;
                })
                .orElse(false);
    }

    /**
     * 批量逻辑删除文档。
     * @param ids 文档ID集合
     * @return 删除数量
     */
    public long deleteByIds(List<ID> ids) {
        return repository.deleteByIdIn(ids);
    }

    /**
     * 高级查询。
     * @param query Spring Data ES 查询对象
     * @return 查询命中结果
     * @throws EsException 查询失败时抛出
     */
    public SearchHits<T> search(Query query) {
        try {
            return elasticsearchOperations.search(query, getEntityClass());
        } catch (Exception e) {
            throw new EsException("Elasticsearch查询失败", e);
        }
    }


    /**
     * 验证分页大小，限定在 1-100 范围，默认 10。
     * @param pageSize 每页大小
     * @return 规范化后的每页大小
     */
    protected int validatePageSize(int pageSize) {
        if (pageSize <= 0) {
            return 10;
        }
        return Math.min(pageSize, 100);
    }

    /**
     * 获取实体类类型（用于泛型解析）。
     * @return 实体类 Class
     */
    protected abstract Class<T> getEntityClass();
}
